#coding=utf8

from scanner import Scanner, T, Token

class DwarfScanner(Scanner):

    #INTERFACE



    #PRIVATE METHODS

    def IsAllowedNearId(self, ch):
        """
        Определяет, может ли символ соседствовать с идентификатором или
        буквенным оператором. """
        return (self.IsWhitespace(ch) or ch == "(" or ch == ")" or ch == "[" or
                ch == "]" or ch == "{" or ch == "}" or ch == "<" or ch == ";" or
                ch == "&" or ch == "." or ch == "=" or ch == "+" or ch == "-" or
                ch == "*" or ch == "!")

    def IsLetter(self, ch):
        """
        Определяет, является ли символ буквой латинского алфавита """
        chL = ch.lower()
        return (chL == "a" or chL == "b" or chL == "c" or chL == "d" or
                chL == "e" or chL == "f" or chL == "g" or chL == "h" or
                chL == "i" or chL == "j" or chL == "k" or chL == "l" or
                chL == "m" or chL == "n" or chL == "o" or chL == "p" or
                chL == "q" or chL == "r" or chL == "s" or chL == "t" or
                chL == "u" or chL == "v" or chL == "w" or chL == "x" or
                chL == "y" or chL == "z")

    def IsStartingNewCommand(self, ch):
        """
        Определяет, может ли символ предшествовать новой команде """
        return (ch == "{" or ch == "}" or ch == ";" or ch == "(" or
                self.IsWhitespace(ch))

    def FindToken(self):
        """
        Возвращает найденный в коде токен, начинающийся с позиции каретки """

        i = self.caretPosition

        if self.IsWhitespace(self.text[i]):
        # ' '
            return Token(T.WHITESPACE, self.text[i])

        if ((self.IsStartingNewCommand(self.text[i - 1]) or
               self.IsWhitespace(self.text[i - 1])) and
              self.text[i : i + 5] == "class" and
              self.IsAllowedNearId(self.text[i + 5])):
        # <'{' | '}' | ';' | whitespace>class<ANI>
            return Token(T.CLASS, self.text[i : i + 5])

        if ((self.IsStartingNewCommand(self.text[i - 1]) or
               self.IsWhitespace(self.text[i - 1])) and
              self.text[i : i + 6] == "public" and
              self.IsAllowedNearId(self.text[i + 6])):
        # <'{' | '}' | ';' | whitespace>public<ANI>
            return Token(T.PUBLIC, self.text[i : i + 6])

        if ((self.IsStartingNewCommand(self.text[i - 1]) or
               self.IsWhitespace(self.text[i - 1])) and
              self.text[i : i + 6] == "static" and
              self.IsAllowedNearId(self.text[i + 6])):
        # <'{' | '}' | ';' | whitespace>static<ANI>
            return Token(T.STATIC, self.text[i : i + 6])

        if ((self.IsStartingNewCommand(self.text[i - 1]) or
               self.IsWhitespace(self.text[i - 1])) and
              self.text[i : i + 4] == "void" and
              self.IsAllowedNearId(self.text[i + 4])):
        # <'{' | '}' | ';' | whitespace>void<whitespace>
            return Token(T.VOID, self.text[i : i + 4])

        if ((self.IsStartingNewCommand(self.text[i - 1]) or
               self.IsWhitespace(self.text[i - 1])) and
              self.text[i : i + 7] == "extends" and
              self.IsAllowedNearId(self.text[i + 7])):
        # <'{' | '}' | ';' | whitespace>extends<whitespace>
            return Token(T.EXTENDS, self.text[i : i + 7])

        if (self.IsWhitespace(self.text[i - 1]) and
              self.text[i : i + 4] == "main" and
              (self.text[i + 4] == "(" or
               self.IsWhitespace(self.text[i + 4]))):
        # <whitespace>main<whitespace | '('>
            return Token(T.MAIN, self.text[i : i + 4])

        if self.text[i] == "(":
        # '('
            return Token(T.LEFT_BRACKET, self.text[i])

        if self.text[i] == ")":
        # ')'
            return Token(T.RIGHT_BRACKET, self.text[i])

        if self.text[i] == "[":
        # '['
            return Token(T.LEFT_QUAD_BRACKET, self.text[i])

        if self.text[i] == "]":
        # ']'
            return Token(T.RIGHT_QUAD_BRACKET, self.text[i])

        if self.text[i] == "{":
        # '{'
            return Token(T.LEFT_FIGURE_BRACKET, self.text[i])

        if self.text[i] == "}":
        # '}'
            return Token(T.RIGHT_FIGURE_BRACKET, self.text[i])

        if self.text[i] == "<":
        # '{'
            return Token(T.LESS, self.text[i])

        if self.text[i] == ".":
        # '.'
            return Token(T.DOT, self.text[i])

        if self.text[i] == ";":
        # ';'
            return Token(T.SEMICOLON, self.text[i])

        if self.text[i] == "=":
        # '='
            return Token(T.EQUAL, self.text[i])

        if self.text[i] == "!":
        # '!'
            return Token(T.EXCLAMATION, self.text[i])

        if self.text[i : i + 2] == "&&":
        # '&&'
            return Token(T.AND, self.text[i : i + 2])

        if (self.IsStartingNewCommand(self.text[i - 1]) and
              self.text[i : i + 6] == "String" and
              self.IsAllowedNearId(self.text[i + 6])):
        # <'{' | '}' | ';' | '(' whitespace>String<ANI>
            return Token(T.STRING, self.text[i : i + 6])

        if (self.IsStartingNewCommand(self.text[i - 1]) and
              self.text[i : i + 3] == "int" and
              self.IsAllowedNearId(self.text[i + 3])):
        # <'{' | '}' | ';' | '(' | whitespace>int<ANI>
            return Token(T.INT, self.text[i : i + 3])

        if (self.IsStartingNewCommand(self.text[i - 1]) and
              self.text[i : i + 7] == "boolean" and
              self.IsAllowedNearId(self.text[i + 7])):
        # <'{' | '}' | ';' | '(' | whitespace>boolean<ANI>
            return Token(T.BOOLEAN, self.text[i : i + 7])

        if (self.IsStartingNewCommand(self.text[i - 1]) and
              self.text[i : i + 2] == "if" and
              self.IsAllowedNearId(self.text[i + 2])):
        # <'{' | '}' | ';' | '(' | whitespace>if<ANI>
            return Token(T.IF, self.text[i : i + 2])

        if (self.IsStartingNewCommand(self.text[i - 1]) and
              self.text[i : i + 4] == "else" and
              self.IsAllowedNearId(self.text[i + 4])):
        # <'{' | '}' | ';' | '(' | whitespace>else<ANI>
            return Token(T.ELSE, self.text[i : i + 4])

        if (self.IsStartingNewCommand(self.text[i - 1]) and
              self.text[i : i + 18] == "System.out.println" and
              (self.text[i + 18] == "(" or
               self.IsWhitespace(self.text[i + 18]))):
        # <'{' | '}' | ';' | '(' | whitespace>System.out.println
        # <'(' | whitespace>
            return Token(T.PRINT, self.text[i : i + 18])

        if (self.IsStartingNewCommand(self.text[i - 1]) and
              self.text[i : i + 6] == "return" and
              self.IsAllowedNearId(self.text[i + 6])):
        # <'{' | '}' | ';' | '(' | whitespace>return<ANI>
            return Token(T.RETURN, self.text[i : i + 6])

        if (self.text[i - 1] == '.' and self.text[i : i + 6] == "length" and
              self.IsAllowedNearId(self.text[i + 6])):
        # .length<ANI>
            return Token(T.LENGTH, self.text[i : i + 6])

        if (self.IsAllowedNearId(self.text[i - 1]) and
              self.text[i : i + 4] == "true" and
              self.IsAllowedNearId(self.text[i + 4])):
        # <ANI>true<ANI>
            return Token(T.TRUE, self.text[i : i + 4])

        if (self.IsAllowedNearId(self.text[i - 1]) and
              self.text[i : i + 5] == "false" and
              self.IsAllowedNearId(self.text[i + 5])):
        # <ANI>false<ANI>
            return Token(T.FALSE, self.text[i : i + 5])

        if (self.IsAllowedNearId(self.text[i - 1]) and
              self.text[i : i + 3] == "new" and
              self.IsAllowedNearId(self.text[i + 3])):
        # <ANI>new<ANI>
            return Token(T.NEW, self.text[i : i + 3])

        # <ANI><identifier><?>
        if self.IsLetter(self.text[i]):
            i1 = 0
            while (self.IsLetter(self.text[i + i1]) or
                   self.text[i + i1].isnumeric()):
                i1 += 1
            id = self.text[i : i + i1]
            if not self.IsAllowedNearId(self.text[i - 1]):
                return Token(T.ERROR, id)
            if self.IsAllowedNearId(self.text[i + i1]):
                return Token(T.IDENTIFIER, id)

        if self.IsAllowedNearId(self.text[i - 1]):
        # <ANI><integer value><?>
            if self.text[i].isnumeric():
                i1 = 1
                while self.text[i + i1].isnumeric():
                    i1 += 1
                value = self.text[i : i + i1]
                if self.IsAllowedNearId(self.text[i + i1]):
                    return Token(T.INTEGER_VALUE, value)
                else:
                    return Token(T.ERROR, value)

        return Token(T.ERROR, self.text[i])